<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>仪表盘</title>
  </head>

  <body>
    <div id="pie"></div>
    <script>
      const pieBox = document.getElementById("pie");
      const sentiment = 2.5,
        totalSentiment = 5,
        bgColor = "rgba(50,111,240,0.1)",
        color = "#326FF0",
        strokeWidth = 16,
        width = 150,
        height = 60;

      function drawElement(tags, parentNode, props, specialDealwith) {
        const element = document.createElementNS(
          "http://www.w3.org/2000/svg",
          tags
        );
        for (const key in props) {
          const value = props[key];
          element.setAttribute(key, value);
        }
        specialDealwith?.(element);
        parentNode.appendChild(element);

        return element;
      }

      const getCircleCommon = (w, h, strokeWidth) => {
        const half = strokeWidth / 2;
        const hR = h - half;
        const wR = (w - half) / 2;
        const r = Math.min(hR, wR);

        const x = w / 2;
        const y = h + half;
        return {
          x,
          y,
          r,
        };
      };

      const getStartEndPointer = ({ x, y, r }) => {
        const beginPointer = { x: x - r, y: y };
        const endPointer = { x: x + r, y: y };

        return {
          beginPointer,
          endPointer,
        };
      };

      function createSvg(parentNode, gap = 10) {
        const h = height + gap + strokeWidth / 2;
        return drawElement("svg", parentNode, { width, height: h });
      }

      function getProgressValue() {
        let value = sentiment / totalSentiment;
        value = 1 - (value > 1 ? 1 : value);

        return value;
      }

      function createPiePath(
        parentNode,
        { beginPointer, endPointer, r, color, ...props },
        specialDealwith
      ) {
        const d = `M ${beginPointer.x} ${beginPointer.y} A ${r} ${r} 0 0 1 ${endPointer.x} ${endPointer.y}`;

        const piePath = drawElement(
          "path",
          parentNode,
          {
            d,
            ...props,
            fill: "none",
            "vector-effect": "non-scaling-stroke",
            stroke: color,
          },
          specialDealwith
        );
      }

      function createPieLine(
        parentNode,
        { beginPointer, endPointer, progressValue, x, y, r }
      ) {
        const center = x + " " + y;
        const deg = 180 * (1 - progressValue);
        const x1 = beginPointer.x - strokeWidth / 2 - 2;
        const y1 = beginPointer.y;
        const x2 = x;
        const y2 = y;
        const transform = `rotate(${deg} ${center})`;
        const strokeDash = strokeWidth + 4;

        drawElement(
          "line",
          parentNode,
          {
            x1,
            y1,
            x2,
            y2,
            stroke: color,
            transform,
            "stroke-dasharray": `${strokeDash} ${r}`,
            "stroke-width": 5,
            "stroke-linecap": "round",
          },
          (line) => {
            const from = `${0} ${center}`;
            const to = `${deg} ${center}`;
            drawElement("animateTransform", line, {
              attributeName: "transform",
              type: "rotate",
              from: from,
              to: to,
              dur: "1s",
              calcMode: "paced",
              repeatCount: "1",
            });
          }
        );
      }

      function init() {
        // 创建一个svg画布
        const svg = createSvg(pieBox);

        // 计算圆半径，圆心坐标，起始终止坐标
        const { x, y, r } = getCircleCommon(width, height, strokeWidth);
        const { beginPointer, endPointer } = getStartEndPointer({ x, y, r });

        // 创建底部半圆
        const bottomPie = createPiePath(svg, {
          beginPointer,
          endPointer,
          r,
          "stroke-width": strokeWidth,
          color: bgColor,
        });

        // 计算进度，并创建进度半圆
        const progressValue = getProgressValue();
        const dashWidth = Math.ceil(Math.PI * r);
        const strokeDashoffset = dashWidth * progressValue;
        const progressPie = createPiePath(
          svg,
          {
            beginPointer,
            endPointer,
            r,
            color,
            "stroke-width": strokeWidth,
            "stroke-dasharray": `${dashWidth} ${dashWidth}`,
            "stroke-dashoffset": `${strokeDashoffset}`,
          },
          (path) => {
            drawElement("animate", path, {
              attributeType: "XML",
              attributeName: "stroke-dashoffset",
              from: dashWidth,
              to: strokeDashoffset,
              dur: "1s",
              calcMode: "paced",
              repeatCount: "1",
            });
          }
        );

        // 创建仪表盘指针
        createPieLine(svg, {
          beginPointer,
          endPointer,
          progressValue,
          x,
          y,
          r,
        });

        // 创建文案
        drawElement(
          "text",
          svg,
          {
            style: "font-size: 20px;font-weight: 700",
            x,
            y: y + 5,
            "text-anchor": "middle",
          },
          (text) => {
            text.textContent = sentiment;
          }
        );
      }

      init();
    </script>
  </body>
</html>
